package realarm.hardwaretest.jniinterface;

import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.util.Log;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.charset.Charset;

public class SerialPortCardManager {

    private static final String TAG = SerialPortCardManager.class.getSimpleName();
    private static final int MSG_ERROR = 0xF0;
    private static final int MSG_READ = 0xF1;
    private static final int MSG_WRITE = 0xF2;
    private static SerialPortCardManager INSTANCE = null;

    private OutputStream mOutputStream;
    private InputStream mInputStream;
    private SerialPort mSerialPort;
    private ReadSerialMessageThread readSerialMessageThread;
    private SerialPortListener mListener = null;

    private Handler mHandler = new Handler(Looper.getMainLooper()) {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            switch (msg.what) {
                case MSG_READ:
                    // 读取数据
                    if (mListener != null) {
                        mListener.onReadResult((String) msg.obj);
                    }
                    break;
                case MSG_WRITE:
                    // 发送数据
                    sendData("result");
                    break;
                case MSG_ERROR:
                    // 错误
                    if (mListener != null) {
                        mListener.onError((String) msg.obj);
                    }
                    break;
                default:
                    break;
            }
        }
    };

    private SerialPortCardManager() {
    }

    public static SerialPortCardManager getInstance() {
        if (INSTANCE == null) {
            synchronized (SerialPortCardManager.class) {
                if (INSTANCE == null) {
                    INSTANCE = new SerialPortCardManager();
                }
            }
        }
        return INSTANCE;
    }

    public void setSerialPortListener(SerialPortListener listener) {
        mListener = listener;
    }

    public void init() {
        init("/dev/ttyS4", 9600);
    }

    public void init(String path, int baudRate) {
        try {
            mSerialPort = new SerialPort(new File(path), baudRate, 0);
            mInputStream = mSerialPort.getInputStream();
            mOutputStream = mSerialPort.getOutputStream();
            readSerialMessageThread = new ReadSerialMessageThread();
            readSerialMessageThread.startRead();
            readSerialMessageThread.continueRead();
        } catch (Exception e) {
            if (mListener != null) {
                mListener.onError(e.getLocalizedMessage());
            }
        }
    }

    /**
     * 串口数据读取线程
     */
    private class ReadSerialMessageThread implements Runnable {
        private boolean isStop = false;
        private boolean isPause = true;
        private Thread thread = null;

        protected void startRead() {
            if (thread == null) {
                thread = new Thread(this, "ReadSerialMessageThread");
                thread.start();
            }
        }

        protected void pauseRead() {
            isPause = true;
        }

        protected synchronized void continueRead() {
            isPause = false;
            notify();
        }

        protected synchronized void stopRead() {
            isPause = false;
            isStop = true;
            notify();
            Thread.interrupted();
        }

        @Override
        public void run() {
            while (!isStop) {
                while (isPause) {
                    synchronized (this) {
                        try {
                            wait();
                        } catch (InterruptedException e) {
                            isPause = false;
                        }
                    }
                }
                try {
                    if (mInputStream == null) {
                        if (mListener != null) {
                            mListener.onError("InputStream is null while reading");
                        }
                        return;
                    }
                    byte[] buffer = new byte[64];
                    int size = mInputStream.read(buffer);
                    // 串口数据，去掉最高位和最低位
                    if (size > 2) {
                        byte[] data = new byte[size - 2];
                        System.arraycopy(buffer, 1, data, 0, size - 2);
                        String result = bytes2HexStr(data);
                        Log.i(TAG, "SerialPort read result: " + result);
                        // 发送消息
                        if (mHandler != null) {
                            mHandler.obtainMessage(MSG_READ, result).sendToTarget();
                        }
                    }
                } catch (Exception e) {
                    if (mHandler != null) {
                        mHandler.obtainMessage(MSG_ERROR, e.getLocalizedMessage()).sendToTarget();
                    }
                }
            }
        }
    }

    /**
     * 发送数据
     *
     * @param data {@linkplain} 数据
     */
    public void sendData(String data) {
        //发送16进制数
        String serialSendDate = hexStr2Str(data);
        try {
            if (mOutputStream != null) {
                Log.i(TAG, "SerialPort write data: " + data);
                mOutputStream.write(str2bytes(serialSendDate));
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 十六进制字符串转换字符串"48454C4C6F41524D" -> HELLoARM
     */
    private static String hexStr2Str(String src) {
        int len = src.length() / 2;
        byte[] ret = new byte[len];
        byte[] tmp = src.getBytes();
        for (int i = 0; i < len; i++) {
            ret[i] = uniteBytes(tmp[i * 2], tmp[i * 2 + 1]);
        }
        return new String(ret);
    }

    /**
     * byte数组转16进制字符串
     */
    private static String bytes2HexStr(byte[] byteArray) {
        StringBuilder sb = new StringBuilder();
        String temp = null;
        for (byte b : byteArray) {
            temp = Integer.toHexString(b & 0xFF);
            if (temp.length() == 1) {
                temp = "0" + temp;
            }
            sb.append(temp);
        }
        return sb.toString();
    }

    private static byte uniteBytes(byte src0, byte src1) {
        byte _b0 = Byte.decode("0x" + new String(new byte[]{src0})).byteValue();
        _b0 = (byte) (_b0 << 4);

        byte _b1 = Byte.decode("0x" + new String(new byte[]{src1})).byteValue();
        byte ret = (byte) (_b0 ^ _b1);

        return ret;
    }

    /**
     * 字节数组转换为字符串'H','E','L','L','O' ->"HELLO"
     */
    private static String bytes2Str(byte[] byteArray) {
        return new String(byteArray, Charset.forName("UTF-8"));
    }

    /**
     * 字符串转换为字节数组"HELLO"->'H','E','L','L','O'
     */
    private static byte[] str2bytes(String string) {
        return string.getBytes();
    }
}
